package com.samehope.ar.socket.support;

import com.samehope.ar.entity.Device;
import com.samehope.ar.entity.SysUser;
import com.samehope.ar.socket.constant.CommandEnum;
import com.samehope.ar.socket.handler.HttpRequestHandler;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description: 用户通道关系
 * @Author: ZhangLuo
 * @Email: 1946430@qq.com
 */
@Slf4j
public class NettyContext {

    /**
     * 用户和通道的关系
     */
    private static Map<Long, Channel> usersMap = new ConcurrentHashMap<>();

    /**
     * 设备和通道的关系 预连接
     */
    private static Map<String, Channel> tempDeviceMap = new ConcurrentHashMap<>();

    /**
     * 已经和手机终端连接的眼睛设备
     */
    private static Map<String, Channel> connectedDeviceMap = new ConcurrentHashMap<>();


    /**
     * 增加用户通道关系
     * @param userId
     * @param channel
     */
    public static void addUser(Long userId, Channel channel) {
        Channel source = getChannel(userId);
        if (source != null) {
            writeMsgAndClose(channel, "[重复连接, 当前连接被断开]");
            return;
        }
        usersMap.put(userId, channel);
    }

    /**
     * 增加预连接的设备通道关系
     * @param deviceMac
     * @param channel
     */
    public static void addTempDevice(String deviceMac, Channel channel) {
        if (getConnectedChannel(deviceMac) != null && getTempChannel(deviceMac) != null) {
            writeMsgAndClose(channel, "[重复连接, 当前连接被断开]");
            return;
        }
        tempDeviceMap.put(deviceMac, channel);
    }

    /**
     * 设置设备通道关系为已连接
     * @param deviceMac
     */
    public static void setConnectedDevice(String deviceMac) {
        Channel channel = getTempChannel(deviceMac);
        if (channel != null) {
            connectedDeviceMap.put(deviceMac, channel);
            tempDeviceMap.remove(deviceMac);
        }
    }

    /**
     * 设置已连接设备关系为预连接
     */
    public static void setTempDeviceMap(String deviceMap) {
        Channel channel = getConnectedChannel(deviceMap);
        if (channel != null) {
            tempDeviceMap.put(deviceMap, channel);
            connectedDeviceMap.remove(deviceMap);
        }
    }

    /**
     * 根据用户获取通道
     * @param userId
     * @return
     */
    public static Channel getChannel(Long userId) {
        return usersMap.get(userId);
    }

    /**
     * 获取已经被连接的通道
     * @param deviceMac
     * @return
     */
    public static Channel getConnectedChannel(String deviceMac) {
        return connectedDeviceMap.get(deviceMac);
    }

    /**
     * 获取临时的通道
     */
    public static Channel getTempChannel(String deviceMac) {
        return tempDeviceMap.get(deviceMac);
    }

    /**
     * 获取用户手机号码
     * @param channel
     * @return
     */
    public static String getMobile(Channel channel) {
        return getUser(channel).getMobile();
    }

    /**
     * 移除通道
     * @param channel
     * @return
     */
    public static void remove(Channel channel) {
        // 预先判断

        if (channel.hasAttr(HttpRequestHandler.USER)) {
            SysUser user = channel.attr(HttpRequestHandler.USER).get();
            usersMap.remove(user.getId());
        }

        Device device = channel.attr(HttpRequestHandler.DEVICE).get();


        if (device != null) {
            connectedDeviceMap.remove(device.getDeviceMac());
            tempDeviceMap.remove(device.getDeviceMac());
        }
    }

    /**
     * 离线通道处理
     * @param channel
     */
    private static void offlineChannelHandle(Channel channel) {
        // 如果有设备属性, 可能是预连接, 也可能是已连接设备的某一端掉线了
        if (channel.hasAttr(HttpRequestHandler.DEVICE)) {
            Device device = channel.attr(HttpRequestHandler.DEVICE).get();
            String deviceMac = device.getDeviceMac();
            if (connectedDeviceMap.containsKey(deviceMac)) {
                // 设备连接
                Channel connectedChannel = getConnectedChannel(deviceMac);

                // 代表是已连接设备设备, 需要通知手机客户端
                SysUser user = channel.attr(HttpRequestHandler.USER).get();
                Channel userChannel = getChannel(user.getId());

                if (channel.equals(userChannel)) {
                    // 如果掉线是用户通道, 需要把设备的连接属性清零, 并放入预连接
                    connectedChannel.attr(HttpRequestHandler.USER).set(null);
                    connectedChannel.attr(HttpRequestHandler.TOKEN).set(null);

                    setTempDeviceMap(deviceMac);
                } else {
                    // 如果不是用户的连接, 那就是设备连接, 需要告诉用户手机终端, 设备已离线
                    writeMsg(user.getId(), MessageBody.of(CommandEnum.DEVICE_OFFLINE, deviceMac).toString());
                }
            }
        }

    }

    /**
     * 获取用户信息
     * @param channel
     * @return
     */
    public static SysUser getUser(Channel channel) {
        if (channel.hasAttr(HttpRequestHandler.USER)) {
            return channel.attr(HttpRequestHandler.USER).get();
        } else {
            return null;
        }
    }

    /**
     * 获取预连接的设备信息
     * @return
     */
    public static List<UserVO> getOnlineUsers() {
        List<UserVO> users = new ArrayList<>();

        for (String deviceMac : connectedDeviceMap.keySet()) {
            Channel channel = getConnectedChannel(deviceMac);
            Device device = channel.attr(HttpRequestHandler.DEVICE).get();
            SysUser user = channel.attr(HttpRequestHandler.USER).get();
            UserVO userVO = new UserVO();
            userVO.setUserId(user.getId());
            userVO.setName(user.getName());
            DeviceVO deviceVO = new DeviceVO();
            deviceVO.setDeviceMac(deviceMac);
            deviceVO.setDeviceName(device.getDeviceName());
            userVO.setDeviceVO(deviceVO);
            users.add(userVO);
        }
        return users;
    }

    /**
     * 获取已连接设备的用户列表
     * @return
     */
    public static List<DeviceVO> getTempDevices() {
        List<DeviceVO> devices = new ArrayList<>();

        for (String deviceMac : tempDeviceMap.keySet()) {
            Channel channel = getTempChannel(deviceMac);
            Device device = channel.attr(HttpRequestHandler.DEVICE).get();
            DeviceVO deviceVO = new DeviceVO();
            deviceVO.setDeviceMac(deviceMac);
            deviceVO.setDeviceName(device.getDeviceName());
            devices.add(deviceVO);
        }
        return devices;
    }

    /**
     * 写出数据, 保持通道
     * @param channel
     * @param msg
     */
    public static void writeMsg(Channel channel, String msg) {
        if (channel == null) {
            return;
        }
        channel.writeAndFlush(new TextWebSocketFrame(msg)).addListener(e -> {
            log.info("成功发送消息给用户: {}, 消息内容: {}", getUser(channel).getMobile(), msg);
        });
    }


    /**
     * 写出数据, 保持通道
     * @param userId
     * @param msg
     */
    public static void writeMsg(Long userId, String msg) {
        Channel channel = getChannel(userId);
        if (channel == null) {
            return;
        }
        channel.writeAndFlush(new TextWebSocketFrame(msg)).addListener(e -> {
            log.info("成功发送消息给用户: {}, 消息内容: {}", getUser(channel).getMobile(), msg);
        });
    }

    /**
     * 写出数据, 然后关闭通道
     * @param channel
     * @param msg
     */
    public static void writeMsgAndClose(Channel channel, String msg) {
        if (channel == null) {
            return;
        }
        channel.writeAndFlush(new TextWebSocketFrame(msg)).addListener((ChannelFutureListener) channelFuture -> {
            channelFuture.channel().close();
        });
    }

}
